#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <shmem.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <msg_queue_peer.h>
#include <stdlib.h>
#include <cJSON.h>
#include <list.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <pthread.h>


#define PATH "/mnt/config/dev_config.json" //数据点表路径
#define DEVNUM 3                           //节点个数

void cjson_jx();

static struct shm_param para;
union val_t {
    int b_val;   //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val; //浮点值存储空间
};

struct std_node
{
    int key;             //唯一键值
    int type;            //数据点类型
    int dev_type;        //数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; //变化上报后需要更新旧值
    union val_t new_val; //从共享内存取出最新数据，放到new_val中
    int ret;             //默认为-1，采集成功后设置为0，采集失败再置-1
};
//消息队列结构体
struct msgbuf
{
    long mtype;
    char mdata[512];
};
struct msg
{
    int key;
    char name[32];
};
struct msg data[DEVNUM];

struct node
{
  uint32_t led;
  uint32_t light;
  float bat;
};

//共享内存线程函数
void *shmsend(void *arg)
{
    int fd;
    fd = open("/dev/ttyUSB0", O_RDWR);
    if (fd < 0)
    {
        perror("msg port  open err");
        exit(0);
    }
    printf("open ok\n");

    struct termios options;
    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_iflag |= IGNPAR;
    options.c_iflag &= ~(ICRNL | IXON);
    options.c_cflag |= (CLOCAL |CREAD);
    options.c_cc[VMIN] =100;
    options.c_cc[VTIME] = 1;
    tcflush(fd, TCIFLUSH);    
    tcsetattr(fd, TCSANOW, &options);
    //*************串口配置***************//
    //定义临时变量来接收从串口发来的数据
    // int led;   //灯
    //int light; //光敏
    //int bat;   //电池
    char buf[24] = "";

    int ret = -1; //初始化共享内存
    ret = shm_init(&para, "shm_test", 1024);
    if (ret < 0)
    {
        printf("shm init err\n");
        exit(0);
    }
    int *addr = (int *)shm_getaddr(&para); //获取共享内存的首地址
    if (addr == NULL)
    {
        printf("shm get err\n");
        exit(0);
    }
    int str_num = *(addr);
    *(addr) = 4;
    struct std_node *v_led;
    struct std_node *v_lig;
    struct std_node *v_bat;

    struct std_node *data_ptr = (struct std_node *)(addr + 1);

    v_led = data_ptr;
    data_ptr += 1;
    v_lig = data_ptr;
    data_ptr += 1;
    v_bat = data_ptr;

    //循环往设备对应的地址里写值
    while (1)
    {
        
        if(read(fd, buf, sizeof(struct node)) == -1)
        {
          printf("shm read port err!\n");
          continue;
        }
        
//        led = *((int *)buf);
//        light = *((int *)(buf + 4));
//        bat = *((int *)(buf + 8));


        struct node *data = buf;
        //v_led->key = 301;
        //v_led->type = 2;
        //v_led->new_val.i_val = led;
        //v_led->ret = 0;
        v_led->new_val.i_val = data->led;

        //v_lig->key = 302;
        // v_lig->type = 2;
        //v_lig->new_val.i_val = light;
        //v_lig->ret = 0;
        v_lig->new_val.i_val = data->light;

        //v_bat->key = 303;
        //v_bat->type = 1;
        //v_bat->new_val.b_val = bat;
        //v_lv_bat->ret = 0;
        v_bat->new_val.f_val = data->bat;
        printf("led:%d light:%d bat:%f\n", v_led->new_val.i_val, v_lig->new_val.i_val, v_bat->new_val.f_val);
        //printf("led:%d light:%d bat:%f\n", led, light, bat);
        sleep(1);
    }
}

void *msgrecv(void *arg) //读消息队列
{
    struct msgbuf recv_buf; //定义接受结构体变量
    // struct msgbuf send_buf; //定义发送结构体变量
    //send_buf.mtype = 1;
    //*************串口配置***************//
   int fd;
    fd = open("/dev/ttyUSB0", O_RDWR);
    if (fd < 0)
    {
        perror("msg port  open err");
        exit(0);
    }
    printf("open ok\n");

    struct termios options;
    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_iflag |= IGNPAR;
    options.c_iflag &= ~(ICRNL | IXON);
    options.c_cflag |= (CLOCAL |CREAD);
    options.c_cc[VMIN] =100;
    options.c_cc[VTIME] = 1;
    tcflush(fd, TCIFLUSH);    
    tcsetattr(fd, TCSANOW, &options);
    //*************串口配置***************//
   
    while (1)
    {
        msg_queue_recv("stm32", &recv_buf, sizeof(recv_buf), 0, 0); //接收从共享内存里发来的JSON信息
        
        cJSON *cjson = cJSON_Parse(recv_buf.mdata);
        if (cjson == NULL) //判断是否转换成功
        {
            perror("msg recv  cjson err!");
            return ;
        }
        //**********解析消息队列**************//
        int key = cJSON_GetObjectItem(cjson, "key")->valueint;
        //根据解析的key值找对应的dev
        //{ key : 12  val : "123"}
         
        ///char val[32] = "asd";

        for (int i = 0; i < DEVNUM; i++)
        {
            if (key == data[i].key)
            {
                cJSON_AddStringToObject(cjson, "dev", data[i].name); //添加name 字符串
            }
        }
        //{ key : 12  val : "123"  dev : }  //dev
        cJSON_DeleteItemFromObject(cjson, "key"); //删除key字符串

        char *str = cJSON_Print(cjson);
        printf("%s\n", str);
        //将str发送到串口
        write(fd, str, strlen(str)); //将JSON信息通过串口发给单片机
        free(str);
        cJSON_Delete(cjson);
        printf("msg  ***** 结束\n");

        pthread_exit(NULL);
    }
}
int main(int argc, char *argv[])
{
     
    cjson_jx();
    pthread_t thread1, thread2;
    if (pthread_create(&thread1, NULL, shmsend, NULL) != 0)
    {
        perror("pthread create err");
        exit(0);
    }
    if (pthread_create(&thread2, NULL, msgrecv, NULL) != 0)
    {
        perror("pthread create err");
        exit(0);
    }

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    return 0;
}
void cjson_jx()
{
    //1.打开文件
    FILE *fd;
    char buf[4096] = "";
    if ((fd = fopen(PATH, "r")) == NULL)
    {
        printf("dev_config.json open err!\n");
        return -1;
    }
    //2.读文件
    fread(buf, 4096, 1, fd);
    printf("%s\n", buf);

    cJSON *root;
    char *str;

    root = cJSON_Parse(buf);

    cJSON *stm32 = cJSON_GetObjectItem(root, "stm32");
    cJSON *array = cJSON_GetObjectItem(stm32, "data");
    cJSON *msg_point;

    str = cJSON_Print(array);
    printf("%s\n", str);
    free(str);
    cJSON *temp;

    for (int i = 0; i < cJSON_GetArraySize(array); i++)
    {
        temp = cJSON_GetArrayItem(array, i);
        msg_point = cJSON_GetObjectItem(temp, "name");
        strcpy(data[i].name, msg_point->valuestring);
        msg_point = cJSON_GetObjectItem(temp, "key");
        data[i].key = msg_point->valueint;
        printf("%s,%d\n", data[i].name, data[i].key);
    }

    cJSON_Delete(root);
}
